package main

import (
	"context"
	authpb "coolcar/v1/auth/api/gen/v1"
	carpb "coolcar/v1/car/api/gen/v1"
	rentalpb "coolcar/v1/rental/api/gen/v1"
	"coolcar/v1/shared/auth"
	"coolcar/v1/shared/zaplog"
	"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
	"github.com/namsral/flag"
	"go.uber.org/zap"
	"log"
	"net/http"
	"net/textproto"

	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials/insecure"
)

var addr = flag.String("addr", ":8080", "address to listen")
var authAddr = flag.String("auth_addr", ":8081", "address to listen")
var tripAddr = flag.String("trip_addr", ":8082", "address to listen")
var profileAddr = flag.String("profile_addr", ":8082", "address to listen")
var carAddr = flag.String("car_addr", ":8084", "address to listen")

func run(sugar *zap.SugaredLogger) error {
	ctx := context.Background()
	ctx, cancel := context.WithCancel(ctx)
	defer cancel()

	// Register gRPC server endpoint
	// Note: Make sure the gRPC server is running properly and accessible
	mux := runtime.NewServeMux(runtime.WithIncomingHeaderMatcher(func(key string) (string, bool) {
		if key == textproto.CanonicalMIMEHeaderKey(runtime.MetadataHeaderPrefix+auth.ImpersonateAccountHeader) {
			return "", false
		}
		return runtime.DefaultHeaderMatcher(key)
	}))
	opts := []grpc.DialOption{grpc.WithTransportCredentials(insecure.NewCredentials())}
	serverConfig := []struct {
		name         string
		addr         string
		registerFunc func(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) error
	}{
		{
			name:         "auth",
			addr:         *authAddr,
			registerFunc: authpb.RegisterAuthServiceHandlerFromEndpoint,
		},
		{
			name:         "trip",
			addr:         *tripAddr,
			registerFunc: rentalpb.RegisterTripServiceHandlerFromEndpoint,
		},
		{
			name:         "profile",
			addr:         *profileAddr,
			registerFunc: rentalpb.RegisterProfileServiceHandlerFromEndpoint,
		},
		{
			name:         "car",
			addr:         *carAddr,
			registerFunc: carpb.RegisterCarServiceHandlerFromEndpoint,
		},
	}

	for _, s := range serverConfig {
		err := s.registerFunc(ctx, mux, s.addr, opts)
		if err != nil {
			sugar.Fatalf("%v: registerFunc failed: %v", s.name, err)
		}
	}

	// Start HTTP server (and proxy calls to gRPC server endpoint)
	return http.ListenAndServe(*addr, mux)
}

func main() {
	flag.Parse()
	sugar, err := zaplog.NewZapLogger()
	if err != nil {
		log.Fatalf("failed to create logger: %v", err)
	}
	defer sugar.Sync()
	sugar.Infof("gateway start server at port: %v", *addr)
	if err := run(sugar); err != nil {
		sugar.Fatal(err)
	}
}
